﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;

namespace Sakura.Silverlight.Extensions
{
	/// <summary>
	/// 表示可以根据内容尺寸限制自动调整分配的均匀网格。
	/// </summary>
	public class AdaptiveUniformGrid : Panel
	{
		/// <summary>
		/// 获取或设置允许单个元素显示的最小高度。
		/// </summary>
		public double ItemMinHeight
		{
			get
			{
				return (double)GetValue(ItemMinHeightProperty);
			}
			set
			{
				SetValue(ItemMinHeightProperty, value);
			}
		}

		/// <summary>
		/// 标识 <see cref="ItemMinHeight" /> 依赖项属性。
		/// </summary>
		public static readonly DependencyProperty ItemMinHeightProperty = DependencyProperty.Register("ItemMinHeight", typeof(double), typeof(AdaptiveUniformGrid), new PropertyMetadata(double.NaN, ItemMinHeightChangedCallback));

		/// <summary>
		/// 当 <see cref="ItemMinHeight" /> 属性更改时引发的回调。
		/// </summary>
		/// <param name="d">引发事件的对象。</param>
		/// <param name="e">事件包含的参数。</param>
		private static void ItemMinHeightChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
		{
			// 代码段自动生成的局部变量。
			var target = (AdaptiveUniformGrid)d;
			var oldValue = (double)e.OldValue;
			var newValue = (double)e.NewValue;

			if (newValue <= 0 || double.IsPositiveInfinity(newValue))
			{
				throw new ArgumentOutOfRangeException("value", "ItemMinHeight 属性值大于零且不能是无穷大。");
			}

			if (oldValue != newValue)
			{
				target.InvalidateMeasure();
			}
		}

		/// <summary>
		/// 获取或设置允许单个元素显示的最小高度。
		/// </summary>
		public double ItemMinWidth
		{
			get
			{
				return (double)GetValue(ItemMinWidthProperty);
			}
			set
			{
				SetValue(ItemMinWidthProperty, value);
			}
		}

		/// <summary>
		/// 标识 <see cref="ItemMinWidth" /> 依赖项属性。
		/// </summary>
		public static readonly DependencyProperty ItemMinWidthProperty = DependencyProperty.Register("ItemMinWidth", typeof(double), typeof(AdaptiveUniformGrid), new PropertyMetadata(double.NaN, ItemMinWidthChangedCallback));

		/// <summary>
		/// 当 <see cref="ItemMinWidth" /> 属性更改时引发的回调。
		/// </summary>
		/// <param name="d">引发事件的对象。</param>
		/// <param name="e">事件包含的参数。</param>
		private static void ItemMinWidthChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
		{
			// 代码段自动生成的局部变量。
			var target = (AdaptiveUniformGrid)d;
			var oldValue = (double)e.OldValue;
			var newValue = (double)e.NewValue;

			if (newValue <= 0 || double.IsPositiveInfinity(newValue))
			{
				throw new ArgumentOutOfRangeException("value", "ItemMinWidth 属性值大于零且不能是无穷大。");
			}

			if (oldValue != newValue)
			{
				target.InvalidateMeasure();
			}
		}

		/// <summary>
		/// 获取或设置实际可以显示的行数。
		/// </summary>
		public int RowCount
		{
			get
			{
				return (int)GetValue(RowCountProperty);
			}
			private set
			{
				SetValue(RowCountProperty, value);
			}
		}

		/// <summary>
		/// 标识 <see cref="RowCount" /> 依赖项属性。
		/// </summary>
		public static readonly DependencyProperty RowCountProperty = DependencyProperty.Register("RowCount", typeof(int), typeof(AdaptiveUniformGrid), new PropertyMetadata(0));


		/// <summary>
		/// 获取或设置实际可以显示的列数。
		/// </summary>
		public int ColumnCount
		{
			get
			{
				return (int)GetValue(ColumnCountProperty);
			}
			private set
			{
				SetValue(ColumnCountProperty, value);
			}
		}

		/// <summary>
		/// 标识 <see cref="ColumnCount" /> 依赖项属性。
		/// </summary>
		public static readonly DependencyProperty ColumnCountProperty = DependencyProperty.Register("ColumnCount", typeof(int), typeof(AdaptiveUniformGrid), new PropertyMetadata(0));

		/// <summary>
		/// 获取或设置实际可以显示的总数目。
		/// </summary>
		public int ItemCount
		{
			get
			{
				return (int)GetValue(ItemCountProperty);
			}
			private set
			{
				SetValue(ItemCountProperty, value);
			}
		}

		/// <summary>
		/// 标识 <see cref="ItemCount" /> 依赖项属性。
		/// </summary>
		public static readonly DependencyProperty ItemCountProperty = DependencyProperty.Register("ItemCount", typeof(int), typeof(AdaptiveUniformGrid), new PropertyMetadata(0));

		/// <summary>
		/// 获取或设置单个元素实际显示的高度。
		/// </summary>
		public double ItemActualHeight
		{
			get
			{
				return (double)GetValue(ItemActualHeightProperty);
			}
			private set
			{
				SetValue(ItemActualHeightProperty, value);
			}
		}

		/// <summary>
		/// 标识 <see cref="ItemActualHeight" /> 依赖项属性。
		/// </summary>
		public static readonly DependencyProperty ItemActualHeightProperty = DependencyProperty.Register("ItemActualHeight", typeof(double), typeof(AdaptiveUniformGrid), new PropertyMetadata(double.NaN));

		/// <summary>
		/// 获取或设置单个元素实际显示的宽度。
		/// </summary>
		public double ItemActualWidth
		{
			get
			{
				return (double)GetValue(ItemActualWidthProperty);
			}
			private set
			{
				SetValue(ItemActualWidthProperty, value);
			}
		}

		/// <summary>
		/// 标识 <see cref="ItemActualWidth" /> 依赖项属性。
		/// </summary>
		public static readonly DependencyProperty ItemActualWidthProperty = DependencyProperty.Register("ItemActualWidth", typeof(double), typeof(AdaptiveUniformGrid), new PropertyMetadata(double.NaN));

		/// <summary>
		/// 获取或设置元素的排列方向。
		/// </summary>
		public Orientation Orientation
		{
			get
			{
				return (Orientation)GetValue(OrientationProperty);
			}
			set
			{
				SetValue(OrientationProperty, value);
			}
		}

		/// <summary>
		/// 标识 <see cref="Orientation" /> 依赖项属性。
		/// </summary>
		public static readonly DependencyProperty OrientationProperty = DependencyProperty.Register("Orientation", typeof(Orientation), typeof(AdaptiveUniformGrid), new PropertyMetadata(Orientation.Horizontal, OrientationChangedCallback));

		/// <summary>
		/// 当 <see cref="Orientation" /> 属性更改时引发的回调。
		/// </summary>
		/// <param name="d">引发事件的对象。</param>
		/// <param name="e">事件包含的参数。</param>
		private static void OrientationChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
		{
			// 代码段自动生成的局部变量。
			var target = (AdaptiveUniformGrid)d;
			var oldValue = (Orientation)e.OldValue;
			var newValue = (Orientation)e.NewValue;

			switch (newValue)
			{
				case Orientation.Horizontal:
				case Orientation.Vertical:
					break;
				default:
					throw new ArgumentException("Orientation 属性不是有效值。", "value");
			}

			if (oldValue != newValue)
			{
				target.InvalidateArrange();
			}
		}

		/// <summary>
		/// 测量子元素在布局中所需的大小，然后确定派生类的大小。
		/// </summary>
		/// <param name="availableSize">此元素可以赋给子元素的可用大小。</param>
		/// <returns>此元素在布局过程中所需的大小，这是由此元素根据对其子元素大小的计算而确定的。</returns>
		protected override Size MeasureOverride(Size availableSize)
		{
			if (double.IsNaN(this.ItemMinHeight))
			{
				this.RowCount = 1;
			}
			else
			{
				var count = (int)Math.Floor(availableSize.Height / this.ItemMinHeight);
				this.RowCount = Math.Max(1, count);
			}

			if (double.IsNaN(this.ItemMinWidth))
			{
				this.ColumnCount = 1;
			}
			else
			{
				var count = (int)Math.Floor(availableSize.Width / this.ItemMinWidth);
				this.ColumnCount = Math.Max(1, count);
			}

			this.ItemCount = this.RowCount * this.ColumnCount;

			this.ItemActualHeight = availableSize.Height / this.RowCount;
			this.ItemActualWidth = availableSize.Width / this.ColumnCount;

			foreach (var i in this.Children)
			{
				i.Measure(new Size
				{
					Width = this.ItemActualWidth,
					Height = this.ItemActualHeight
				});
			}

			return base.MeasureOverride(availableSize);
		}

		/// <summary>
		/// 定位子元素并确定派生类的大小。
		/// </summary>
		/// <param name="finalSize">父级中此元素应用来排列自身及其子元素的最终区域。</param>
		/// <returns>所用的实际大小。</returns>
		protected override Size ArrangeOverride(Size finalSize)
		{
			for (var i = 0; i < this.Children.Count; i++)
			{
				var child = this.Children[i];

				int rowIndex, colIndex;

				switch (this.Orientation)
				{
					case System.Windows.Controls.Orientation.Horizontal:
						rowIndex = i / this.ColumnCount;
						colIndex = i - rowIndex * this.ColumnCount;
						break;
					case System.Windows.Controls.Orientation.Vertical:
						colIndex = i / this.RowCount;
						rowIndex = i - colIndex * this.RowCount;
						break;
					// 不会发生。
					default:
						throw new InvalidOperationException("Orientation 属性值无效。");
				}

				var x = colIndex * this.ItemActualWidth;
				var y = rowIndex * this.ItemActualHeight;

				child.Arrange(new Rect
				{
					X = x,
					Y = y,
					Height = this.ItemActualHeight,
					Width = this.ItemActualWidth
				});
			}

			return base.ArrangeOverride(finalSize);
		}
	}
}
